#include "../include/GameManager.hh"
#include <iostream>
#include <cstdlib>
#include <limits>

namespace Game {
    // Initialize game and show character selection
    void GameManager::startGame() {
        system("cls");
        std::cout << "=== CHOOSE YOUR HERO ===\n";
        std::cout << "1. Select Character\n2. View Character Info\nChoice: ";
        int choice;
        std::cin >> choice;

        if (choice == 2) {
            showCharacterInfo();
            startGame(); // Recursive call to return to selection
            return;
        }

        std::string name;
        int classChoice;
        std::cout << "Enter your name: ";
        std::cin >> name;
        std::cout << "Choose class (1-Warrior, 2-Mage, 3-Rogue): ";
        std::cin >> classChoice;

        // Initialize player with chosen class
        player_ = Player(name, static_cast<Player::Class>(classChoice - 1));
        system("cls");
        gameLoop();
    }

    // Display character class info
    void GameManager::showCharacterInfo() {
        system("cls");
        std::cout << "=== CHARACTER INFO ===\n";
        std::cout << "1. Warrior: High HP (120) and Defense (10)\n";
        std::cout << "2. Mage: High Attack (20), Low Defense (5)\n";
        std::cout << "3. Rogue: Balanced (100 HP, 18 ATK, 7 DEF) with 20% Crit Chance\n";
        std::cout << "Press Enter to return...";
        std::cin.ignore(std::numeric_limits<std::streamsize>::max(), '\n');
        std::cin.get();
    }

    // Main game loop
    void GameManager::gameLoop() {
        while (player_.isAlive()) {
            showMainMenu();
        }
        std::cout << "Game Over!\n";
    }

    // Display main menu and handle choices
    void GameManager::showMainMenu() {
        system("cls");
        Room* currentRoom = gameMap_.getCurrentRoom();
        gameMap_.printMap();

        // Display room info
        std::cout << "\n== " << currentRoom->getDesc() << " ==\n";
        std::cout << "Room Type: ";
        switch (currentRoom->getType()) {
            case Room::TRAP: std::cout << "Trap"; break;
            case Room::HEALING: std::cout << "Healing"; break;
            case Room::BOSS: std::cout << "Boss"; break;
            case Room::START: std::cout << "Start";break;
            default: std::cout << "Normal";
        }

        // Display room contents
        std::cout << "\nItems here: ";
        auto& loot = currentRoom->getLoot();
        if (loot.empty()) std::cout << "None";
        else {
            for (auto& item : loot) std::cout << item->getName() << " ";
        }

        std::cout << "\nEnemies here: ";
        if (currentRoom->getEnemy()) {
            std::cout << currentRoom->getEnemy()->getName()
                      << " (HP: " << currentRoom->getEnemy()->getHealth() << ")";
        } else std::cout << "None";

        // Player status
        std::cout << "\nYour HP: " << player_.getHealth() << "\n";
        std::cout << "1. Move\n2. Attack\n3. Take Item\n4. Inventory\n5. Stats\n6. Quit\nChoice: ";
        
        int choice;
        std::cin >> choice;

        switch (choice) {
            case 1: 
                handleMovement(); 
                break;
            case 2: {
                Enemy* enemy = currentRoom->getEnemy();
                if (enemy) handleCombat(*enemy);
                else std::cout << "No enemies here!\n";
                break;
            }
            case 3: {
                if (!loot.empty()) {
                    player_.addItem(loot.back().release());
                    loot.pop_back();
                } else std::cout << "No items to take!\n";
                break;
            }
            case 4:
                player_.displayInventory();
                std::cout << "Press Enter to continue...";
                std::cin.ignore();
                std::cin.get();
                break;
            case 5:
                player_.showStats();
                std::cout << "Press Enter to continue...";
                std::cin.ignore();
                std::cin.get();
                break;
            case 6: 
                exit(0);
            default: 
                std::cout << "Invalid choice!\n";
        }
    }

    // Handle combat logic
    void GameManager::handleCombat(Enemy& enemy) {
        int round = 1;
        bool escaped = false;
        lastCombatLog_.clear();

        while (player_.isAlive() && enemy.isAlive() && !escaped) {
            system("cls");
            std::cout << "=== ROUND " << round << " ===\n";
            if (!lastCombatLog_.empty()) {
                std::cout << lastCombatLog_ << "\n";
            }
            std::cout << "Your HP: " << player_.getHealth() << "\n";
            std::cout << enemy.getName() << " HP: " << enemy.getHealth() << "\n";
            std::cout << "1. Attack\n2. Use Item\n3. Escape\nChoice: ";
            int choice;
            std::cin >> choice;

            switch (choice) {
                case 1: {
                    unsigned damage = player_.calculateDamage(enemy.getDefense());
                    bool isCritical = (damage > (player_.getAttack() - enemy.getDefense()));
                    enemy.takeDamage(damage);
                    lastCombatLog_ = ">> You attacked " + enemy.getName() + "! ";
                    if (isCritical) lastCombatLog_ += "(Critical!) ";
                    lastCombatLog_ += "Deals " + std::to_string(damage) + " damage!";

                    if (enemy.isAlive()) {
                        enemy.attack(player_);
                        lastCombatLog_ += "\n" + enemy.getLastActionLog();
                    }
                    break;
                }
                case 2: {
                    player_.displayInventory();
                    if (player_.getInventorySize() == 0) {
                        std::cout << "No items to use\n";
                        break;
                    }
                    int itemIndex;
                    std::cout << "Select item (1-" << player_.getInventorySize() << "): ";
                    std::cin >> itemIndex;
                    if (itemIndex > 0 && itemIndex <= player_.getInventorySize()) {
                        Item* item = player_.getInventory()[itemIndex - 1].get();
                        player_.useItem(itemIndex - 1);
                        // Clearly display item effects
                        lastCombatLog_ = ">> Used " + item->getName() + 
                                        " (HP+" + std::to_string(item->getHealthBoost()) +
                                        ", ATK+" + std::to_string(item->getAttackBoost()) +
                                        ", DEF+" + std::to_string(item->getDefenseBoost()) + ")";
                    }
                    if (enemy.isAlive()) {
                        enemy.attack(player_);
                        lastCombatLog_ += "\n" + enemy.getLastActionLog();
                    }
                    break;
                }
                case 3: {
                    if (player_.tryEscape()) {
                        lastCombatLog_ = ">> You escaped successfully!";
                        escaped = true;
                    } else {
                        lastCombatLog_ = ">> Escape failed!";
                        enemy.attack(player_);
                        lastCombatLog_ += "\n" + enemy.getLastActionLog();
                    }
                    break;
                }
                default:
                    std::cout << "Invalid choice!\n";
                    continue;
            }

            // Check if enemy is defeated
            if (!enemy.isAlive()) {
                std::cout << "\n=== You defeated " << enemy.getName() << "! ===\n";
                std::cout << ">> Gained " << enemy.getExpReward() << " EXP!\n";
                unsigned exp = enemy.getExpReward();
                player_.gainExp(exp); 
                auto drop = enemy.generateDrop();
                if (drop) {
                    std::cout << ">> Obtained " << drop->getName()
                              << " (HP+" << drop->getHealthBoost()
                              << ", ATK+" << drop->getAttackBoost()
                              << ", DEF+" << drop->getDefenseBoost() << ")\n";
                    player_.addItem(drop.release());
                }
                gameMap_.getCurrentRoom()->clearEnemy();

                // Check if in boss room for victory
                if (gameMap_.isInBossRoom()) {
                    std::cout << "\n=== VICTORY! You defeated the final boss! ===\n";
                    exit(0);
                } else {
                    std::cout << "Press Enter to continue...";
                    std::cin.ignore();
                    std::cin.get();
                }
                break;
            }
            round++;
        }
    }

    // Handle player movement
    void GameManager::handleMovement() {
        Room* currentRoom = gameMap_.getCurrentRoom();
        if (currentRoom->getEnemy()) {
            std::cout << ">> You must defeat " << currentRoom->getEnemy()->getName() << " first!\n";
            std::cout << "Press Enter to continue...";
            std::cin.ignore();
            std::cin.get();
            return;
        }

        std::string dir;
        std::cout << "Enter direction (north/south/east/west): ";
        std::cin >> dir;

        if (!gameMap_.movePlayer(dir)) {
            std::cout << "Cannot move that way!\n";
        } else {
            currentRoom = gameMap_.getCurrentRoom();
            currentRoom->enter(player_); // Trigger room effects (e.g., trap/healing)
        }
    }
}
